/*
 * Copyright (c) 2018.
 * http://www.ulabcare.com
 */

package com.mt.roll.upms.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.mt.roll.core.api.Assert;
import com.mt.roll.core.base.BaseSupport;
import com.mt.roll.core.dal.entity.SysMenu;
import com.mt.roll.core.dal.entity.SysMenuResource;
import com.mt.roll.core.dal.entity.SysRole;
import com.mt.roll.core.dal.entity.SysRoleMenu;
import com.mt.roll.core.dal.service.SysMenuResourceServiceBiz;
import com.mt.roll.core.dal.service.SysMenuServiceBiz;
import com.mt.roll.core.dal.service.SysRoleMenuServiceBiz;
import com.mt.roll.core.dal.service.SysRoleServiceBiz;
import com.mt.roll.core.params.EnabledParam;
import com.mt.roll.core.params.IdListParam;
import com.mt.roll.core.params.IdParam;
import com.mt.roll.core.utils.TreeUtil;
import com.mt.roll.core.vo.*;
import com.mt.roll.upms.mapper.MenuMapper;
import com.mt.roll.upms.params.MenuParam;
import com.mt.roll.upms.params.MenuQueryParam;
import com.mt.roll.upms.params.RoleMenuParam;
import com.mt.roll.upms.service.MenuService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 菜单服务实现类
 *
 * @author jiff
 * @date 2018/11/9
 * @since 1.0
 */
@Service
@Transactional
public class MenuServiceImpl extends BaseSupport implements MenuService {

    @Autowired
    private SysMenuServiceBiz sysMenuServiceBiz;

    @Autowired
    private SysRoleMenuServiceBiz sysRoleMenuServiceBiz;
    @Autowired
    private SysMenuResourceServiceBiz sysMenuResourceServiceBiz;
    @Autowired
    private SysRoleServiceBiz sysRoleServiceBiz;

    @Autowired
    private MenuMapper menuMapper;


    /**
     * 获取菜单
     *
     * @param idParam
     * @return
     */
    @Override
    public R<MenuVo> get(IdParam idParam) {
        SysMenu menu = sysMenuServiceBiz.getById(idParam.getId());
        Assert.notNull("菜单不存在", menu);
        MenuVo sysMenuVo = MenuVo.builder().build();
        BeanUtils.copyProperties(menu, sysMenuVo);
        //父菜单ID存在时，则返回父菜单名称
        if (menu.getParentId() > 0L) {
            SysMenu parentMenu = sysMenuServiceBiz.getById(menu.getParentId());
            if (parentMenu != null) {
                sysMenuVo.setParentName(parentMenu.getName());
            }
        }
        return successful(sysMenuVo);
    }

    /**
     * 获取菜单列表
     *
     * @param menuQueryParam
     * @return
     */
    @Override
    public R<List<MenuVo>> list(MenuQueryParam menuQueryParam) {
        QueryWrapper<SysMenu> wrapper = new QueryWrapper<>();
        wrapper.eq(ObjectUtils.isNotNull(menuQueryParam.getParentId()), SysMenu.PARENT_ID, menuQueryParam.getParentId())
                .eq(ObjectUtils.isNotNull(menuQueryParam.getCategory()), SysMenu.CATEGORY, menuQueryParam.getCategory())
                .eq(ObjectUtils.isNotNull(menuQueryParam.getType()), SysMenu.TYPE, menuQueryParam.getType())
                .eq(ObjectUtils.isNotNull(menuQueryParam.getEnabled()), SysMenu.ENABLED, menuQueryParam.getEnabled())
                .like(StringUtils.isNotBlank(menuQueryParam.getCode()), SysMenu.CODE, menuQueryParam.getCode())
                .like(StringUtils.isNotBlank(menuQueryParam.getName()), SysMenu.NAME, menuQueryParam.getName());
        List<SysMenu> menus = sysMenuServiceBiz.list(wrapper);
        List<MenuVo> menuVos = com.mt.roll.core.utils.BeanUtils.copyList(menus, MenuVo.class);
        return successful(menuVos);
    }

    /**
     * 获取分页菜单列表
     *
     * @param menuQueryParam
     * @return
     */
    @Override
    public R<PageVo<MenuVo>> page(MenuQueryParam menuQueryParam) {
        QueryWrapper<SysMenu> wrapper = new QueryWrapper<>();
        wrapper.eq(ObjectUtils.isNotNull(menuQueryParam.getParentId()), SysMenu.PARENT_ID, menuQueryParam.getParentId())
                .eq(ObjectUtils.isNotNull(menuQueryParam.getCategory()), SysMenu.CATEGORY, menuQueryParam.getCategory())
                .eq(ObjectUtils.isNotNull(menuQueryParam.getType()), SysMenu.TYPE, menuQueryParam.getType())
                .eq(ObjectUtils.isNotNull(menuQueryParam.getEnabled()), SysMenu.ENABLED, menuQueryParam.getEnabled())
                .like(StringUtils.isNotBlank(menuQueryParam.getCode()), SysMenu.CODE, menuQueryParam.getCode())
                .like(StringUtils.isNotBlank(menuQueryParam.getName()), SysMenu.NAME, menuQueryParam.getName());
        IPage<SysMenu> page = sysMenuServiceBiz.page(new Page<>(menuQueryParam.getCurrent(), menuQueryParam.getSize()), wrapper);
        return successful(new PageVo<>(page, MenuVo.class));
    }

    /**
     * 新增菜单
     *
     * @param menuParam
     * @return
     */
    @Override
    public R<IdVo> add(MenuParam menuParam) {
        int parentMenuLevel = 0;
        if (menuParam.getParentId() > 0L) {
            SysMenu parentMenu = sysMenuServiceBiz.getById(menuParam.getParentId());
            Assert.notNull("父菜单不存在", parentMenu);
            Assert.eq(parentMenu.getCategory(), menuParam.getCategory(), "菜单分类和父菜单分类不一致");
            parentMenuLevel = parentMenu.getLevel();
        }
        SysMenu menu = new SysMenu();
        BeanUtils.copyProperties(menuParam, menu);
        menu.setLevel(parentMenuLevel + 1);
        setCommonField(menu);
        sysMenuServiceBiz.save(menu);
        return successful(IdVo.builder().id(menu.getId()).build());
    }

    /**
     * 更新菜单
     *
     * @param menuParam
     * @return
     */
    @Override
    public R<IdVo> update(MenuParam menuParam) {
        SysMenu menu = sysMenuServiceBiz.getById(menuParam.getId());
        Assert.notNull("菜单不存在", menu);
        //暂时不允许修改父菜单和菜单分类，涉及到菜单层级计算和分类判断
        SysMenu updateMenu = new SysMenu();
        BeanUtils.copyProperties(menuParam, updateMenu, "parentId", "category");
        setUpdateCommonField(updateMenu);
        sysMenuServiceBiz.updateById(updateMenu);
        return successful(IdVo.builder().id(menu.getId()).build());
    }

    /**
     * 启用停用
     *
     * @param enabledParam
     * @return
     */
    @Override
    public R<IdVo> enabled(EnabledParam enabledParam) {
        SysMenu menu = new SysMenu().setId(enabledParam.getId());
        menu.setEnabled(enabledParam.getEnabled());
        setUpdateCommonField(menu);
        sysMenuServiceBiz.updateById(menu);
        return successful(IdVo.builder().id(menu.getId()).build());
    }

    /**
     * 删除菜单
     *
     * @param idParam
     * @return
     */
    @Override
    public R<IdVo> delete(IdParam idParam) {
        Assert.eqZero(sysRoleMenuServiceBiz.count(new QueryWrapper<SysRoleMenu>().eq(SysRoleMenu.MENU_ID, idParam.getId())), "菜单还关联角色");
        //删除菜单资源关系
        sysMenuResourceServiceBiz.remove(new QueryWrapper<SysMenuResource>().eq(SysMenuResource.MENU_ID, idParam.getId()));
        sysMenuServiceBiz.removeById(idParam.getId());
        return successful(IdVo.builder().id(idParam.getId()).build());
    }

    /**
     * 批量删除菜单
     *
     * @param idListParam
     * @return
     */
    @Override
    public R<IdListVo> delete(IdListParam idListParam) {
        return null;
    }

    /**
     * 保存角色菜单
     *
     * @param roleMenuParam 角色菜单参数
     * @return 主键列表
     */
    @Override
    public R<IdListVo> saveRoleMenu(RoleMenuParam roleMenuParam) {
        Long roleId = roleMenuParam.getRoleId();
        SysRole role = sysRoleServiceBiz.getById(roleId);
        Assert.notNull("角色不存在", role);
        //检查设置的角色是否都存在
        List<Long> menuIds = roleMenuParam.getMenuIds();
        if (CollectionUtils.isNotEmpty(menuIds)) {
            Collection<SysMenu> menus = sysMenuServiceBiz.listByIds(menuIds);
            if (menuIds.size() != menus.size()) {
                return failed("菜单不存在");
            }
            for (SysMenu menu : menus) {
                Assert.eq(role.getCategory(), menu.getCategory(), "菜单分类和角色分类不一致");
            }
        }
        //先删除原有的角色菜单关系
        sysRoleMenuServiceBiz.remove(new QueryWrapper<SysRoleMenu>().eq(SysRoleMenu.ROLE_ID, roleId));
        if (CollectionUtils.isNotEmpty(menuIds)) {
            List<SysRoleMenu> roleMenus = menuIds.stream()
                    .map(menuId -> setCommonField(new SysRoleMenu().setRoleId(roleId).setMenuId(menuId)))
                    .collect(Collectors.toList());
            sysRoleMenuServiceBiz.saveBatch(roleMenus);
            return successful(IdListVo.builder().ids(roleMenus.stream().map(SysRoleMenu::getId).collect(Collectors.toList())).build());
        }

        return successful(null);
    }

    /**
     * 获取菜单列表
     *
     * @param idParam 主键参数
     * @return 菜单列表
     */
    @Override
    public R<List<MenuVo>> listByRole(IdParam idParam) {
        SysRole role = sysRoleServiceBiz.getById(idParam.getId());
        Assert.notNull("角色不存在", role);
        List<MenuVo> menuVos = menuMapper.listByRole(idParam.getId(), role.getCategory());
        return successful(TreeUtil.toTree(menuVos));
    }
}
